#pragma once
/**********
 * 此模块为compile和runner的封装
 * 其功能为：
 * 适配用户请求，定制通信协议字段
 * 正确调用compile和runner
 * 形成唯一的文件名
 * 主要逻辑：
 * 1.首先上层传递给stat函数两个Json串，用来反序列化和序列化。
 * 2.stat函数先对in_json进行反序列化，拿到用户提交的代码，输入，以及限制，然后利用毫秒时间戳和原子性唯一值构建唯一的文件名称
 * 3.将code代码写入到利用文件名生成的源文件中，并调用编译与运行模块进行操作。
 * 4.整个过程运行的状态输入到status中，并利用StatusToDesc进行描述转换
 * 5.最后利用json构建输出返回给上层
 * 6.调用RemoveTempFile函数清理掉形成的临时文件
 */
#include "runner.hpp"
#include "compile.hpp"
namespace ns_compile_and_run
{
    using namespace ns_compiler;
    using namespace ns_util;
    using namespace ns_runner;
    using namespace ns_log;
    class CompileAndRun
    {
    public:
        //此函数的功能为将temp路径下的临时文件全部清空
        static void RemoveTempFile(const std::string& file_name)
        {
            std::string src_file = PathUtil::Src(file_name);
            //unlink函数：将文件删除
            if(FileUtil::IsFileExists(src_file))
                unlink(src_file.c_str());
            std::string exe_file = PathUtil::Exe(file_name);
            if(FileUtil::IsFileExists(exe_file))
                unlink(exe_file.c_str());
            std::string comp_file = PathUtil::CompileError(file_name);
            if(FileUtil::IsFileExists(comp_file))
                unlink(comp_file.c_str());
            std::string stdin_file = PathUtil::Stdin(file_name);
            if(FileUtil::IsFileExists(stdin_file))
                unlink(stdin_file.c_str());
            std::string stdout_file = PathUtil::Stdout(file_name);
            if(FileUtil::IsFileExists(stdout_file))
                unlink(stdout_file.c_str());
            std::string stderr_file = PathUtil::Stderr(file_name);
            if(FileUtil::IsFileExists(stderr_file))
                unlink(stderr_file.c_str());
        }

        // 此函数的功能为将status对应的状态码转换为字符描述
        static std::string StatusToDesc(int status, const std::string &file_name)
        {
            std::string desc;
            switch (status)
            {
            case CODE_SUCCESS:
                desc = "编译运行成功";
                break;
            case CODE_NULL_ERR:
                desc = "提交代码为空";
                break;
            case CODE_UNKNOW_ERR:
                desc = "未知错误";
                break;
            case CODE_COMPILE_ERR:
                // desc = "编译错误";
                FileUtil::ReadFile(PathUtil::CompileError(file_name), &desc, true);
                desc = "编译错误\n"+desc;
                break;
            case SIGABRT: // 6
                desc = "内存超过限制";
                break;
            case SIGXCPU: // 24
                desc = "时间超过限制";
                break;
            case SIGFPE: // 8
                desc = "浮点数溢出";
                break;
            default:
                desc = "Unknow: " + std::to_string(status);
                break;
            }
            return desc;
        }
        /********************************
         * 输入:
         * code:用户提交的代码
         * input:用户给自己提交的代码对应的参数
         * cpu_limit:用户代码的时间限制
         * mem_limit:用户代码的空间限制
         * 输出:
         * 必填:
         * status:状态码
         * reason:请求结果
         * 选填:
         * stdout:程序运行完的结果
         * stderr:程序运行完的错误结果
         *
         * in_json = {"code": "#include...", "input": "","cpu_limit":1, "mem_limit":10240}
         * out_json = {"status":"0", "reason":"","stdout":"","stderr":"",}
         *********************************/
        // 此函数的功能为将上层提供过来的json串进行反序列化，将用户代码code提取并进行编译和运行，最后构建json类型的应答返回给上层
        static void Start(const std::string &in_json, std::string *out_json)
        {
            // 解析json字符串---反序列化
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);

            std::string code = in_value["code"].asString();
            std::string input = in_value["input"].asString();
            int cpu_limit = in_value["cpu_limit"].asInt();
            int mem_limit = in_value["mem_limit"].asInt();

            int status_code = 0;   // 代码状态值
            std::string file_name; // 形成唯一文件名
            int run_result = 0;    // 运行模块返回值
            Json::Value out_Value; // 输出的json串

            if (code.size() == 0) // 代码为空
            {
                status_code = CODE_NULL_ERR;
                goto END;
            }

            // 调用函数形成唯一文件名
            file_name = FileUtil::UniqFileName();

            // 将code写入到形成的临时文件中
            if (!FileUtil::WriteFile(PathUtil::Src(file_name), code))
            {
                // 写入文件失败
                status_code = CODE_UNKNOW_ERR;
                goto END;
            }
            // 编译文件
            if (!Compiler::Compile(file_name))
            {
                // 编译文件失败
                status_code = CODE_COMPILE_ERR;
                goto END;
            }
            // 运行文件
            run_result = Runner::Run(file_name, cpu_limit, mem_limit);
            if (run_result < 0)
            {
                status_code = CODE_UNKNOW_ERR; // 运行内部错误
            }
            else if(run_result>0)
            {
                status_code = run_result;
            }
            else
            {
                status_code = 0; //==0,运行成功.>0程序异常
            }
        END:
            // 设定json输出
            out_Value["status"] = status_code;
            out_Value["reason"] = StatusToDesc(status_code, file_name);
            if (status_code == 0) // 整个运行编译过程成功
            {
                std::string std_out;
                FileUtil::ReadFile(PathUtil::Stdout(file_name), &std_out, true);
                out_Value["stdout"] = std_out;

                std::string std_err;
                FileUtil::ReadFile(PathUtil::Stderr(file_name), &std_err, true);
                out_Value["stderr"] = std_err;
            }
            Json::StyledWriter writer;
            *out_json = writer.write(out_Value);

            //清除生成的临时文件
            RemoveTempFile(file_name);

        }
    };
}